﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Web.Profile;
using Db8.Data;
using Db8.DataAccess;
using System.Configuration;

namespace Db8.Providers
{
    public class Db8ProfileProvider : ProfileProvider
    {
        public override string ApplicationName { get; set; }

        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }
            if (string.IsNullOrEmpty(name))
            {
                name = "Db8ProfileProvider";
            }
            if (string.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "Profile Provider for Db8");
            }

            base.Initialize(name, config);

            ApplicationName = config["applicationName"];
            if (string.IsNullOrEmpty(ApplicationName))
                ApplicationName = "/";
        }

        public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
        {
            using (Db8Context db = new Db8Context())
            {
                var users = db.Users.Where(u => u.LastActivityDt <= userInactiveSinceDate).ToArray();
                int deleted = 0;
                foreach (var user in users)
                {
                    db.Users.Remove(user);
                    deleted++;
                }
                db.SaveChanges();
                return deleted;
            }
        }

        public override int DeleteProfiles(string[] usernames)
        {
            using (Db8Context db = new Db8Context())
            {
                var users = db.Users.WhereIn(u => u.Username, usernames).ToArray();
                int deleted = 0;
                foreach (var user in users)
                {
                    db.Users.Remove(user);
                    deleted++;
                }
                db.SaveChanges();
                return deleted;
            }
        }

        public override int DeleteProfiles(ProfileInfoCollection profilesToDelete)
        {
            using (Db8Context db = new Db8Context())
            {
                string[] usernames = profilesToDelete.Cast<ProfileInfo>().Select(pi => pi.UserName).ToArray();
                var users = db.Users.WhereIn(u => u.Username, usernames).ToArray();
                int deleted = 0;
                foreach (var user in users)
                {
                    db.Users.Remove(user);
                    deleted++;
                }
                db.SaveChanges();
                return deleted;
            }
        }

        public override ProfileInfoCollection FindInactiveProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
        {
            using (Db8Context db = new Db8Context())
            {
                ProfileInfoCollection pic = new ProfileInfoCollection();
                var qry = db.Users
                    .Where(u => u.Username.Contains(usernameToMatch) && u.LastActivityDt <= userInactiveSinceDate);
                totalRecords = qry.Count();
                foreach (var user in qry.OrderBy(u => u.UserId).Skip(pageIndex * pageSize).Take(pageSize))
                {
                    pic.Add(CreateProfileInfo(user));
                }
                return pic;
            }
        }

        public override ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            using (Db8Context db = new Db8Context())
            {
                ProfileInfoCollection pic = new ProfileInfoCollection();
                var qry = db.Users.Where(u => u.Username.Contains(usernameToMatch));
                totalRecords = qry.Count();
                foreach (var user in qry.OrderBy(u => u.UserId).Skip(pageIndex * pageSize).Take(pageSize))
                {
                    pic.Add(CreateProfileInfo(user));
                }
                return pic;
            }
        }

        public override ProfileInfoCollection GetAllInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
        {
            using (Db8Context db = new Db8Context())
            {
                ProfileInfoCollection pic = new ProfileInfoCollection();
                var qry = db.Users.Where(u => u.LastActivityDt <= userInactiveSinceDate);
                totalRecords = qry.Count();
                foreach (var user in qry.OrderBy(u => u.UserId).Skip(pageIndex * pageSize).Take(pageSize))
                {
                    pic.Add(CreateProfileInfo(user));
                }
                return pic;
            }
        }

        public override ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, int pageIndex, int pageSize, out int totalRecords)
        {
            using (Db8Context db = new Db8Context())
            {
                ProfileInfoCollection pic = new ProfileInfoCollection();
                var qry = db.Users;
                totalRecords = qry.Count();
                foreach (var user in qry.OrderBy(u => u.UserId).Skip(pageIndex * pageSize).Take(pageSize))
                {
                    pic.Add(CreateProfileInfo(user));
                }
                return pic;
            }
        }

        public override int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
        {
            using (Db8Context db = new Db8Context())
            {
                ProfileInfoCollection pic = new ProfileInfoCollection();
                var qry = db.Users.Where(u => u.LastActivityDt <= userInactiveSinceDate);
                return qry.Count();
            }
        }

        public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
        {
            using (Db8Context db = new Db8Context())
            {
                SettingsPropertyValueCollection settings = new SettingsPropertyValueCollection();

                string username = context["Username"] as string;
                long? userId = context["UserId"] as long?;

                User user = db.Users.Where(u => u.Username == username).FirstOrDefault();
                if (user == null && userId != null)
                    user = db.Users.Where(u => u.UserId == userId).FirstOrDefault();
                if (user != null)
                {
                    foreach (SettingsProperty property in collection)
                    {
                        SettingsPropertyValue value = new SettingsPropertyValue(property);
                        switch (property.Name)
                        {
                            case "UserId":
                                value.PropertyValue = user.UserId;
                                break;
                            case "Email":
                                value.PropertyValue = user.Email;
                                break;
                            case "Name":
                                value.PropertyValue = user.Name;
                                break;
                            case "FirstName":
                                value.PropertyValue = user.FirstName;
                                break;
                            case "MiddleName":
                                value.PropertyValue = user.MiddleName;
                                break;
                            case "LastName":
                                value.PropertyValue = user.LastName;
                                break;
                            case "Picture":
                                value.PropertyValue = "http://graph.facebook.com/" + user.UserId + "/picture";
                                break;
                            case "Score":
                                value.PropertyValue = user.Score;
                                break;
                            case "AccessToken":
                                value.PropertyValue = user.AccessToken;
                                break;
                            case "LastUpdatedDt":
                                value.PropertyValue = user.LastUpdatedDt;
                                break;
                            case "LastActivityDt":
                                value.PropertyValue = user.LastActivityDt;
                                break;
                            default:
                                break;
                        }
                        settings.Add(value);
                    }
                }
                return settings;
            }
        }

        public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection)
        {
            using (Db8Context db = new Db8Context())
            {
                string username = context["Username"] as string;
                long? userId = context["UserId"] as long?;

                User user = db.Users.Where(u => u.Username == username).FirstOrDefault();
                if (user == null && userId != null)
                    user = db.Users.Where(u => u.UserId == userId).FirstOrDefault();
                if (user != null)
                {
                    foreach (SettingsPropertyValue value in collection)
                    {
                        switch (value.Property.Name)
                        {
                            case "Email":
                                user.Email = (value.PropertyValue as string) ?? user.Email;
                                break;
                            case "Name":
                                user.Name = (value.PropertyValue as string) ?? user.Name;
                                break;
                            case "FirstName":
                                user.FirstName = (value.PropertyValue as string) ?? user.FirstName;
                                break;
                            case "MiddleName":
                                user.MiddleName = (value.PropertyValue as string) ?? user.MiddleName;
                                break;
                            case "LastName":
                                user.LastName = (value.PropertyValue as string) ?? user.LastName;
                                break;
                            case "Score":
                                user.Score = (value.PropertyValue as int?) ?? user.Score;
                                break;
                            case "AccessToken":
                                user.AccessToken = (value.PropertyValue as string) ?? user.AccessToken;
                                break;
                            case "LastUpdatedDt":
                                user.LastUpdatedDt = (value.PropertyValue as DateTime?) ?? user.LastUpdatedDt;
                                break;
                            case "LastActivityDt":
                                user.LastActivityDt = (value.PropertyValue as DateTime?) ?? user.LastActivityDt;
                                break;
                            default:
                                break;
                        }
                        
                    }

                    // update LastUpdatedDt
                    user.LastUpdatedDt = DateTime.UtcNow;
                    db.SaveChanges();
                }
            }



        }

        private ProfileInfo CreateProfileInfo(User user)
        {
            return new ProfileInfo(user.Username, false, user.LastActivityDt, user.LastUpdatedDt, 0);
        }
    }
}
